package sdp;

import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;

import com.googlecode.javacv.*;
import com.googlecode.javacv.cpp.*;
import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_highgui.*;
import static com.googlecode.javacv.cpp.opencv_video.*;
import static com.googlecode.javacv.cpp.opencv_features2d.*;
import static com.googlecode.javacv.cpp.opencv_contrib.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
import static com.googlecode.javacv.cpp.opencv_calib3d.*;


public class Vision {
        public static int RED    = 0;
        public static int YELLOW = 1;
        public static int BLUE   = 2;
       
        enum Mode {
                RAW,
                CHANNELS
        }
       
        private boolean firstRun      = true;
        private int     minValue      = 95;
        private int     minSaturation = 78;
        private Mode    mode          = Mode.RAW;
       
        int[] minHue = { 0,  15, 75  };
        int[] maxHue = { 15, 33, 103 };
       
        CvRect crop = cvRect(7, 63, 629, 332);
       
        public void setMode( Mode mode ) {
                this.mode = mode;
        }
       
        public void setMinHue( int colour, int newValue ) {
                minHue[ colour ] = newValue;
        }
       
        public void setMaxHue( int colour, int newValue ) {
                maxHue[ colour ] = newValue;
        }
       
        public void setMinValue( int newValue ) {
                minValue = newValue;
        }
       
        public void setMinSaturation( int newValue ) {
                minSaturation = newValue;
        }
       
        public int getMinValue() {
                return minValue;
        }
       
        public int getMinSaturation() {
                return minSaturation;
        }
       
        public int getMinHue( int colour ) {
                return minHue[ colour ];
        }
       
        public int getMaxHue( int colour ) {
                return maxHue[ colour ];
        }
       
        public void setCropLeft( int newValue ) {
                crop.x( newValue );
        }
       
        public void setCropTop( int newValue ) {
                crop.y( newValue );
        }
       
        public void setCropWidth( int newValue ) {
                crop.width( newValue );
        }
       
        public void setCropHeight( int newValue ) {
                crop.height( newValue );
        }
       
        public int getCropLeft() {
                return crop.x();
        }
       
        public int getCropTop() {
                return crop.y();
        }
       
        public int getCropWidth() {
                return crop.width();
        }
       
        public int getCropHeight() {
                return crop.height();
        }
       
        public BufferedImage drawChessboardCorners( BufferedImage frame ) {
                source = makeIplImage( frame );
                IplImage gray = newImage(1);
                cvCvtColor(source, gray, CV_BGR2GRAY);
                CvSize chessSize = cvSize(8, 5);
                CvPoint2D32f corners = new CvPoint2D32f( chessSize.width() * chessSize.height() );
                int[] count = new int[ 1 ];
               
               
                int r = cvFindChessboardCorners(source, chessSize, corners, count, CV_CALIB_CB_ADAPTIVE_THRESH);
                cvDrawChessboardCorners(source, chessSize, corners, count[0], r);
               
                return source.getBufferedImage();
        }
       
        public BufferedImage showChannels( BufferedImage frame ) {
                source = applyCrop( makeIplImage(frame) );
               
                IplImage hsv  = newImage(3), hue = newImage(1), sat = newImage(1), val = newImage(1);
                IplImage tmp1 = newImage(1), tmp2 = newImage(1), tmp3 = newImage(1), satAndVal = newImage(1);
                IplImage[] channels = new IplImage[3];
               
                cvCvtColor(source, hsv, CV_BGR2HSV);
                cvSplit(hsv,hue,sat,val,null);
                cvThreshold( sat, tmp1, minSaturation, 255, CV_THRESH_BINARY );
                cvThreshold( val, tmp2, minValue,      255, CV_THRESH_BINARY );
                cvAnd( tmp1,tmp2,satAndVal,null);
               
                for( int i = 0 ; i < 3 ; ++ i ) {
                        channels[ i ] = newImage(1);
                        cvThreshold( hue, tmp1, minHue[i], 255, CV_THRESH_BINARY );
                        cvThreshold( hue, tmp2, maxHue[i], 255, CV_THRESH_BINARY_INV );
                        cvAnd( tmp1, tmp2,      tmp1, null );
                        cvAnd( tmp1, satAndVal, channels[ i ],  null );
                }
               
                cvMerge(channels[2], channels[1], channels[0], null, source);
               
                return source.getBufferedImage();
        }
       
        public BufferedImage showRaw( BufferedImage frame ) {
                source = applyCrop( makeIplImage(frame) );
                return source.getBufferedImage();
        }
       
        public BufferedImage processImage( BufferedImage frame, RobotState robot1, RobotState robot2, BallState ball ) {
                if( mode == Mode.RAW )
                        return showRaw( frame );
                else if( mode == Mode.CHANNELS )
                        return showChannels( frame );
               
                return null;
        }
       
        private IplImage newImage( int channels ) {
                return IplImage.create( cvGetSize(source), source.depth(), channels );
        }
       
        private void createImages(  ) {
        }
       
        private IplImage applyCrop( IplImage raw ) {
                IplImage r = IplImage.create( cvSize(crop.width(), crop.height()), raw.depth(), 3 );
               
                if( crop.x() < 0 ) crop.x(0);
                if( crop.y() < 0 ) crop.y(0);
                if( crop.width() > raw.width() )   crop.width(raw.width());
                if( crop.height() > raw.height() ) crop.height(raw.height());
               
                cvSetImageROI(raw, crop);
                cvCopy(raw, r);
               
                return r;
        }
       
        private IplImage makeIplImage( BufferedImage frame ) {
                ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
                ColorModel cm = new ComponentColorModel(cs, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
                BufferedImage copy = new BufferedImage(cm, frame.copyData(null), false, null);
                return IplImage.createFrom(copy);
        }
       
        private IplImage source;
       
        private static final int N_ONE_CHANNEL_IMAGES   = 9;
        private static final int N_THREE_CHANNEL_IMAGES = 8;
}

